package com.zenithmind.library.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zenithmind.common.result.PageResult;
import com.zenithmind.common.result.Result;
import com.zenithmind.common.result.ResultCode;
import com.zenithmind.library.mapper.AuthorMapper;
import com.zenithmind.library.mapper.AuthorStatisticsMapper;
import com.zenithmind.library.pojo.domain.Author;
import com.zenithmind.library.pojo.domain.AuthorStatistics;
import com.zenithmind.library.pojo.dto.AuthorCreateDTO;
import com.zenithmind.library.pojo.dto.AuthorUpdateDTO;
import com.zenithmind.library.pojo.query.AuthorQuery;
import com.zenithmind.library.pojo.vo.AuthorVO;
import com.zenithmind.library.service.AuthorService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 作者服务实现类
 * 
 * @author ZenithMind
 * @since 2024-06-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthorServiceImpl extends ServiceImpl<AuthorMapper, Author> implements AuthorService {

    private final AuthorMapper authorMapper;
    private final AuthorStatisticsMapper authorStatisticsMapper;

    @Override
    @Cacheable(value = "authors", key = "'page:' + #query.hashCode()")
    public PageResult<AuthorVO> getAuthorPage(AuthorQuery query) {
        log.info("分页查询作者，查询条件：{}", query);

        Page<AuthorVO> page = query.toPage();
        IPage<AuthorVO> result = authorMapper.selectAuthorPage(page, query);

        return PageResult.of(result.getRecords(), result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    @Cacheable(value = "authors", key = "'detail:' + #id")
    public AuthorVO getAuthorDetail(String id) {
        log.info("查询作者详情，ID：{}", id);
        
        Author author = getById(id);
        if (author == null) {
            throw new RuntimeException("作者不存在");
        }
        
        return convertToVO(author);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "authors", allEntries = true)
    public Result<AuthorVO> createAuthor(AuthorCreateDTO createDTO) {
        log.info("创建作者，数据：{}", createDTO);
        
        // 检查作者姓名是否已存在
        if (existsByName(createDTO.getName(), null)) {
            return Result.fail(ResultCode.CONFLICT.getCode(), "作者姓名已存在", null);
        }
        
        // 转换为实体对象
        Author author = new Author();
        BeanUtils.copyProperties(createDTO, author);
        
        author.setStatus(1); // 默认启用
        // 注意：作品数量现在由AuthorStatistics实体管理 // 初始作品数量为0
        author.setTotalBorrowCount(0L); // 初始借阅次数为0
        author.setCreateTime(LocalDateTime.now());
        author.setUpdateTime(LocalDateTime.now());
        
        // 保存作者
        boolean saved = save(author);
        if (!saved) {
            return Result.fail(ResultCode.FAIL.getCode(), "创建作者失败", null);
        }
        
        // 返回创建的作者信息
        AuthorVO authorVO = convertToVO(author);
        return Result.success(authorVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "authors", allEntries = true)
    public Result<AuthorVO> updateAuthor(String id, AuthorUpdateDTO updateDTO) {
        log.info("更新作者，ID：{}，数据：{}", id, updateDTO);
        
        // 检查作者是否存在
        Author existingAuthor = getById(id);
        if (existingAuthor == null) {
            return Result.fail(ResultCode.NOT_FOUND.getCode(), "作者不存在", null);
        }
        
        // 检查作者姓名是否已被其他作者使用
        if (StringUtils.hasText(updateDTO.getName()) && 
            existsByName(updateDTO.getName(), id)) {
            return Result.fail(ResultCode.CONFLICT.getCode(), "作者姓名已被其他作者使用", null);
        }
        
        // 更新作者信息
        Author author = new Author();
        BeanUtils.copyProperties(updateDTO, author);
        author.setId(id);
        author.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(author);
        if (!updated) {
            return Result.fail(ResultCode.FAIL.getCode(), "更新作者失败", null);
        }
        
        // 返回更新后的作者信息
        Author updatedAuthor = getById(id);
        AuthorVO authorVO = convertToVO(updatedAuthor);
        return Result.success(authorVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "authors", allEntries = true)
    public Result<Void> deleteAuthor(String id) {
        log.info("删除作者，ID：{}", id);
        
        // 检查作者是否存在
        Author author = getById(id);
        if (author == null) {
            return Result.fail(ResultCode.NOT_FOUND.getCode(), "作者不存在", null);
        }
        
        // 检查是否有图书
        try {
            AuthorStatistics stats = authorStatisticsMapper.selectByAuthorId(id);
            if (stats != null && stats.getBookCount() != null && stats.getBookCount() > 0) {
                return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(), "该作者下还有图书，无法删除", null);
            }
        } catch (Exception e) {
            log.warn("检查作者作品数量失败，作者ID：{}，继续删除操作", id, e);
        }
        
        // 删除作者
        boolean deleted = removeById(id);
        if (!deleted) {
            return Result.fail(ResultCode.FAIL.getCode(), "删除作者失败", null);
        }
        
        return Result.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "authors", allEntries = true)
    public Result<Void> batchDeleteAuthors(List<String> ids) {
        log.info("批量删除作者，IDs：{}", ids);
        
        // 检查每个作者是否可以删除
        for (String id : ids) {
            Author author = getById(id);
            if (author == null) {
                return Result.fail(ResultCode.NOT_FOUND.getCode(), "作者不存在：" + id, null);
            }
            
            // 检查是否有图书
            try {
                AuthorStatistics stats = authorStatisticsMapper.selectByAuthorId(id);
                if (stats != null && stats.getBookCount() != null && stats.getBookCount() > 0) {
                    return Result.fail(ResultCode.PRECONDITION_FAILED.getCode(),
                        "作者《" + author.getName() + "》下还有图书，无法删除", null);
                }
            } catch (Exception e) {
                log.warn("检查作者作品数量失败，作者ID：{}，继续删除操作", id, e);
            }
        }
        
        // 批量删除
        boolean deleted = removeByIds(ids);
        if (!deleted) {
            return Result.fail(ResultCode.FAIL.getCode(), "批量删除作者失败", null);
        }
        
        return Result.success();
    }

    @Override
    @CacheEvict(value = "authors", allEntries = true)
    public Result<Void> enableAuthor(String id) {
        log.info("启用作者，ID：{}", id);
        return updateAuthorStatus(id, 1);
    }

    @Override
    @CacheEvict(value = "authors", allEntries = true)
    public Result<Void> disableAuthor(String id) {
        log.info("禁用作者，ID：{}", id);
        return updateAuthorStatus(id, 0);
    }

    @Override
    @Cacheable(value = "authors", key = "'name:' + #name")
    public List<AuthorVO> getAuthorsByName(String name) {
        log.info("根据姓名查询作者，姓名：{}", name);
        return authorMapper.selectByName(name);
    }

    @Override
    @Cacheable(value = "authors", key = "'book:' + #bookId")
    public List<AuthorVO> getAuthorsByBookId(String bookId) {
        log.info("根据图书ID查询作者，图书ID：{}", bookId);
        return authorMapper.selectByBookId(bookId);
    }

    @Override
    public List<AuthorVO> searchAuthors(String keyword, Integer limit) {
        log.info("搜索作者，关键词：{}，限制数量：{}", keyword, limit);
        return authorMapper.searchAuthors(keyword, limit);
    }

    @Override
    @Cacheable(value = "authors", key = "'hot:' + #limit")
    public List<AuthorVO> getHotAuthors(Integer limit) {
        log.info("获取热门作者，限制数量：{}", limit);
        return authorMapper.selectHotAuthors(limit);
    }

    @Override
    @Cacheable(value = "authors", key = "'productive:' + #limit")
    public List<AuthorVO> getProductiveAuthors(Integer limit) {
        log.info("获取高产作者，限制数量：{}", limit);
        return authorMapper.selectProductiveAuthors(limit);
    }

    @Override
    @CacheEvict(value = "authors", allEntries = true)
    public Result<Void> updateAuthorBookCount(String authorId) {
        log.info("更新作者作品数量，作者ID：{}", authorId);

        if (authorId == null || authorId.trim().isEmpty()) {
            return Result.fail(ResultCode.PARAM_ERROR.getCode(), "作者ID不能为空", null);
        }

        try {
            // 检查作者是否存在
            Author author = getById(authorId);
            if (author == null) {
                return Result.fail(ResultCode.NOT_FOUND.getCode(), "作者不存在", null);
            }

            // 重新计算作品数量
            int updateCount = authorStatisticsMapper.recalculateBookCount(authorId);
            if (updateCount > 0) {
                log.info("更新作者作品数量成功，作者ID：{}", authorId);
                return Result.success();
            } else {
                log.warn("更新作者作品数量失败，可能统计记录不存在，作者ID：{}", authorId);
                return Result.fail(ResultCode.NOT_FOUND.getCode(), "作者统计记录不存在", null);
            }
        } catch (Exception e) {
            log.error("更新作者作品数量失败，作者ID：{}", authorId, e);
            return Result.fail(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "更新作者作品数量失败", null);
        }
    }

    @Override
    @CacheEvict(value = "authors", allEntries = true)
    public Result<Void> incrementAuthorBookCount(String authorId) {
        log.info("增加作者作品数量，作者ID：{}", authorId);
        
        int updated = authorMapper.incrementBookCount(authorId);
        if (updated == 0) {
            return Result.fail(ResultCode.FAIL.getCode(), "更新作者作品数量失败", null);
        }
        
        return Result.success();
    }

    @Override
    @CacheEvict(value = "authors", allEntries = true)
    public Result<Void> decrementAuthorBookCount(String authorId) {
        log.info("减少作者作品数量，作者ID：{}", authorId);
        
        int updated = authorMapper.decrementBookCount(authorId);
        if (updated == 0) {
            return Result.fail(ResultCode.FAIL.getCode(), "更新作者作品数量失败", null);
        }
        
        return Result.success();
    }

    @Override
    @CacheEvict(value = "authors", allEntries = true)
    public Result<Void> updateAuthorTotalBorrowCount(String authorId) {
        log.info("更新作者总借阅次数，作者ID：{}", authorId);

        if (authorId == null || authorId.trim().isEmpty()) {
            return Result.fail(ResultCode.PARAM_ERROR.getCode(), "作者ID不能为空", null);
        }

        try {
            // 检查作者是否存在
            Author author = getById(authorId);
            if (author == null) {
                return Result.fail(ResultCode.NOT_FOUND.getCode(), "作者不存在", null);
            }

            // 重新计算总借阅次数
            int updateCount = authorStatisticsMapper.recalculateTotalBorrowCount(authorId);
            if (updateCount > 0) {
                log.info("更新作者总借阅次数成功，作者ID：{}", authorId);
                return Result.success();
            } else {
                log.warn("更新作者总借阅次数失败，可能统计记录不存在，作者ID：{}", authorId);
                return Result.fail(ResultCode.NOT_FOUND.getCode(), "作者统计记录不存在", null);
            }
        } catch (Exception e) {
            log.error("更新作者总借阅次数失败，作者ID：{}", authorId, e);
            return Result.fail(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "更新作者总借阅次数失败", null);
        }
    }

    @Override
    @CacheEvict(value = "authors", allEntries = true)
    public Result<Void> incrementAuthorTotalBorrowCount(String authorId) {
        log.info("增加作者总借阅次数，作者ID：{}", authorId);
        
        int updated = authorMapper.incrementTotalBorrowCount(authorId);
        if (updated == 0) {
            return Result.fail(ResultCode.FAIL.getCode(), "更新作者总借阅次数失败", null);
        }
        
        return Result.success();
    }

    @Override
    public boolean existsByName(String name, String excludeId) {
        return authorMapper.existsByName(name, excludeId);
    }

    @Override
    public Result<String> importAuthors(List<AuthorCreateDTO> authors) {
        log.info("导入作者数据，数量：{}", authors.size());

        if (authors == null || authors.isEmpty()) {
            return Result.fail(ResultCode.PARAM_ERROR.getCode(), "导入数据不能为空", null);
        }

        int successCount = 0;
        int failCount = 0;
        StringBuilder errorMessages = new StringBuilder();

        for (int i = 0; i < authors.size(); i++) {
            AuthorCreateDTO authorDTO = authors.get(i);
            try {
                // 数据验证
                if (authorDTO.getName() == null || authorDTO.getName().trim().isEmpty()) {
                    failCount++;
                    errorMessages.append("第").append(i + 1).append("行：作者姓名不能为空；");
                    continue;
                }

                // 检查姓名是否重复
                if (existsByName(authorDTO.getName(), null)) {
                    failCount++;
                    errorMessages.append("第").append(i + 1).append("行：作者姓名已存在；");
                    continue;
                }

                // 创建作者
                Result<AuthorVO> createResult = createAuthor(authorDTO);
                if (createResult.isSuccess()) {
                    successCount++;
                } else {
                    failCount++;
                    errorMessages.append("第").append(i + 1).append("行：").append(createResult.getMsg()).append("；");
                }
            } catch (Exception e) {
                failCount++;
                errorMessages.append("第").append(i + 1).append("行：").append(e.getMessage()).append("；");
                log.error("导入第{}行数据失败", i + 1, e);
            }
        }

        String resultMessage = String.format("导入完成，成功：%d条，失败：%d条", successCount, failCount);
        if (failCount > 0) {
            resultMessage += "。失败原因：" + errorMessages.toString();
        }

        log.info("作者数据导入完成，成功：{}条，失败：{}条", successCount, failCount);
        return Result.success(resultMessage);
    }

    @Override
    public Result<String> exportAuthors(AuthorQuery query) {
        log.info("导出作者数据，查询条件：{}", query);

        try {
            // 1. 查询数据
            if (query == null) {
                query = new AuthorQuery();
            }

            // 设置较大的分页大小以获取所有数据
            query.setSize(10000); // 最多导出10000条记录
            PageResult<AuthorVO> pageResult = getAuthorPage(query);

            if (pageResult == null || pageResult.getRecords() == null || pageResult.getRecords().isEmpty()) {
                return Result.fail(ResultCode.NOT_FOUND.getCode(), "没有找到符合条件的作者数据", null);
            }

            // 2. 生成Excel文件路径
            String timestamp = String.valueOf(System.currentTimeMillis());
            String fileName = "authors_export_" + timestamp + ".xlsx";
            String filePath = "/exports/" + fileName;

            // 3. 这里应该实现实际的Excel生成逻辑
            // 由于没有具体的Excel工具类，这里只是模拟
            log.info("模拟生成Excel文件，包含{}条记录，文件路径：{}", pageResult.getRecords().size(), filePath);

            // 实际项目中，这里应该：
            // - 使用EasyExcel或Apache POI生成Excel文件
            // - 将文件保存到指定目录
            // - 返回文件的访问URL或下载链接

            String resultMessage = String.format("导出成功，共%d条记录，文件：%s",
                pageResult.getRecords().size(), fileName);

            log.info("作者数据导出完成，记录数：{}，文件：{}", pageResult.getRecords().size(), fileName);
            return Result.success(resultMessage);

        } catch (Exception e) {
            log.error("导出作者数据失败", e);
            return Result.fail(ResultCode.INTERNAL_SERVER_ERROR.getCode(), "导出失败：" + e.getMessage(), null);
        }
    }

    /**
     * 更新作者状态
     */
    private Result<Void> updateAuthorStatus(String id, Integer status) {
        Author author = new Author();
        author.setId(id);
        author.setStatus(status);
        author.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(author);
        if (!updated) {
            return Result.fail(ResultCode.FAIL.getCode(), "更新作者状态失败", null);
        }
        
        return Result.success();
    }

    /**
     * 转换为VO对象
     */
    private AuthorVO convertToVO(Author author) {
        AuthorVO authorVO = new AuthorVO();
        BeanUtils.copyProperties(author, authorVO);
        return authorVO;
    }
}
